This project presents a simple segment-based chain simulation built using p5.js, where multiple connected segments move and follow each other in a two-dimensional space.
Class Explanation
Constructor Method
The Seg class defines a single segment. Each segment has:
VectA: the vector representing the segment's position.
rest: a small offset distance to maintain smooth proportional motion.
parent: a reference to the segment it follows.
The moveTo method smoothly moves a segment toward a target point (px, py).
It calculates the vector from the segment to the target, measures the distance to determine how far the segment should move and moves the segment there.
moveTo(px, py){
let target = createVector(px, py);
let dirVec = p5.Vector.sub(target, this.VectA);
let dist = dirVec.mag();
dirVec.normalize();
dirVec.mult(dist);
this.VectA.add(dirVec);
}
Follow Method
The follow method makes a segment follow its parent segment while keeping the correct distance by:
1st Calculating the vector pointing from the segment to its parent.
2nd Finding the difference between the current distance and the desired rest length.
3rd Moving the segment proportionally to this difference, keeping connections stable yet flexible.
follow(parent){
this.parent = parent;
let dirVec = p5.Vector.sub(parent.VectA, this.VectA);
let dist = dirVec.mag();
let error = dist - this.rest;
dirVec.normalize();
dirVec.mult(error - this.rest);
this.VectA.add(dirVec);
}
Show Method
The show method draws the segment on the screen, visualizing both the connection and the segment's point.
It Draws a line from the segment to its parent, draws a circle at the segment's position, representing a joint and allows customization of circle color, size, and line thickness.
A main segment acts as the head of the chain and follows the mouse cursor, controlling the movement of the rest of the segments in a hierarchical way.
arms[0].moveTo(mouseX, mouseY);
Around it, other segments are linked sequentially. Each segment follows the previous segment while maintaining a proportional distance defined by the rest parameter, which ensures smooth motion and avoids abrupt jumps.
During the simulation, all segments are updated continuously. The head segment moves toward the mouse, and all child segments follow their parent segment with proportional correction.
for (var i = 0; i < arms.length; i++) {
if (i === 0) {
arms[0].moveTo(mouseX, mouseY);
} else {
arms[i].follow(arms[i - 1]);
}
arms[i].show(color(255), 2, color(0), 10);
}
The movement of each segment is calculated using vectors: the vector from the current segment to its target (the parent segment or the mouse) determines the direction and distance. By normalizing the vector and scaling it proportionally to the distance error, each segment moves smoothly, creating a flexible, snake-like chain.
50
Full Sketch
let numberOfSegments = 10;
let restLength = 15;
let arms = [];
function setup() {
createCanvas(400, 400);
for (var i = 0; i < numberOfSegments; i++){
arms.push(new Seg(-i, height/2, restLength));
}
arms[0].parent = arms[0];
}
function draw() {
background(220);
for (var i = 0; i < arms.length; i++) {
if (i === 0) {
arms[0].moveTo(mouseX, mouseY);
} else {
arms[i].follow(arms[i - 1]);
}
arms[i].show(color(255), 2, color(0), 10);
}
}